package logic

import (
	"context"
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v4"
	"github.com/iriver/ai-offer/backend/internal/model"
	"github.com/iriver/ai-offer/backend/internal/svc"
	"github.com/iriver/ai-offer/backend/internal/types"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpx"
)

type RefreshTokenLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RefreshTokenLogic {
	return &RefreshTokenLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *RefreshTokenLogic) RefreshToken(req *types.RefreshTokenRequest) (resp *types.TokenResponse, err error) {
	// 验证刷新令牌
	claims, err := parseToken(req.RefreshToken, l.svcCtx.Config.Auth.RefreshSecret)
	if err != nil {
		l.Logger.Errorf("刷新令牌验证失败: %v", err)
		return nil, httpx.NewCodeError(types.ErrTokenInvalid, "无效的刷新令牌")
	}

	// 从令牌中获取用户ID
	userId, ok := claims["userId"].(float64)
	if !ok {
		l.Logger.Error("从刷新令牌中获取用户ID失败")
		return nil, httpx.NewCodeError(types.ErrTokenInvalid, "无效的刷新令牌")
	}

	// 查询用户
	user, err := l.svcCtx.UserStore.FindOne(int64(userId))
	if err != nil {
		if err == model.ErrNotFound {
			l.Logger.Infof("用户不存在: %d", int64(userId))
			return nil, httpx.NewCodeError(types.ErrUserNotFound, "用户不存在")
		}
		l.Logger.Errorf("查询用户失败: %v", err)
		return nil, httpx.NewCodeError(types.ErrDatabase, "令牌刷新失败，请稍后重试")
	}

	// 生成新的访问令牌
	now := time.Now().Unix()
	accessClaims := make(jwt.MapClaims)
	accessClaims["exp"] = now + l.svcCtx.Config.Auth.AccessExpire
	accessClaims["iat"] = now
	accessClaims["userId"] = user.ID
	accessClaims["email"] = user.Email
	accessClaims["role"] = user.Role
	accessToken := jwt.New(jwt.SigningMethodHS256)
	accessToken.Claims = accessClaims
	newAccessToken, err := accessToken.SignedString([]byte(l.svcCtx.Config.Auth.AccessSecret))
	if err != nil {
		l.Logger.Errorf("生成新的访问令牌失败: %v", err)
		return nil, httpx.NewCodeError(types.ErrTokenGeneration, "令牌刷新失败")
	}

	// 生成新的刷新令牌
	refreshClaims := make(jwt.MapClaims)
	refreshClaims["exp"] = now + l.svcCtx.Config.Auth.RefreshExpire
	refreshClaims["iat"] = now
	refreshClaims["userId"] = user.ID
	refreshToken := jwt.New(jwt.SigningMethodHS256)
	refreshToken.Claims = refreshClaims
	newRefreshToken, err := refreshToken.SignedString([]byte(l.svcCtx.Config.Auth.RefreshSecret))
	if err != nil {
		l.Logger.Errorf("生成新的刷新令牌失败: %v", err)
		return nil, httpx.NewCodeError(types.ErrTokenGeneration, "令牌刷新失败")
	}

	// 返回新的令牌
	resp = &types.TokenResponse{
		AccessToken:  newAccessToken,
		RefreshToken: newRefreshToken,
		ExpiresAt:    now + l.svcCtx.Config.Auth.AccessExpire,
		TokenType:    "Bearer",
	}

	l.Logger.Infof("用户令牌刷新成功: %d", int64(userId))
	return resp, nil
}

// 解析JWT令牌
func parseToken(tokenString, secret string) (jwt.MapClaims, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("unexpected signing method")
		}
		return []byte(secret), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, errors.New("invalid token")
}
